#include "http_server.h"
#include <iostream>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sstream>
#include <fstream>
#include <sys/stat.h>
#include <algorithm>
#include <atomic>

// 构造函数
HttpServer::HttpServer(int port) : epoll_fd_(-1), server_fd_(-1), port_(port), thread_pool_(8) {
    // 初始化服务器
    if (!init_server()) {
        std::cerr << "Server initialization failed!" << std::endl;
        exit(EXIT_FAILURE);
    }
}

// 析构函数
HttpServer::~HttpServer() {
    if (server_fd_ != -1) {
        close(server_fd_);
    }
    if (epoll_fd_ != -1) {
        close(epoll_fd_);
    }
}

// 启动服务器
void HttpServer::start() {
    std::cout << "Server started on port " << port_ << std::endl;
    
    while (true) {
        // 等待事件发生，超时时间1秒用于检查超时连接
        int nfds = epoll_wait(epoll_fd_, events_, MAX_EVENTS, 1000);
        if (nfds == -1) {
            std::cerr << "epoll_wait failed: " << strerror(errno) << std::endl;
            continue;
        }
        
        // 检查超时连接
        check_timeouts();
        
        // 处理事件
        for (int i = 0; i < nfds; ++i) {
            // 新的连接请求
            if (events_[i].data.fd == server_fd_) {
                handle_new_connection();
            } 
            // 已连接的客户端数据
            else {
                handle_client_data(events_[i].data.fd);
            }
        }
    }
}

// 初始化服务器
bool HttpServer::init_server() {
    // 创建服务器套接字
    server_fd_ = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd_ == -1) {
        perror("socket failed");
        return false;
    }

    // 设置套接字选项，允许端口复用
    int opt = 1;
    if (setsockopt(server_fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
        perror("setsockopt failed");
        close(server_fd_);
        return false;
    }

    // 绑定地址和端口
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(INADDR_ANY);
    address.sin_port = htons(port_);
    
    if (bind(server_fd_, (struct sockaddr *)&address, sizeof(address)) == -1) {
        perror("bind failed");
        close(server_fd_);
        return false;
    }

    // 开始监听，最大等待队列长度为1024
    if (listen(server_fd_, 1024) == -1) {
        perror("listen failed");
        close(server_fd_);
        return false;
    }

    // 创建epoll实例
    epoll_fd_ = epoll_create1(0);
    if (epoll_fd_ == -1) {
        perror("epoll_create1 failed");
        close(server_fd_);
        return false;
    }

    // 将服务器套接字添加到epoll
    struct epoll_event event;
    event.data.fd = server_fd_;
    //检测 server_fd_ 读缓冲区是否有数据
    event.events = EPOLLIN;  
    if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, server_fd_, &event) == -1) {
        perror("epoll_ctl failed");
        close(server_fd_);
        close(epoll_fd_);
        return false;
    }

    return true;
}

// 处理新的连接
void HttpServer::handle_new_connection() {
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    
    // 接受新连接
    int client_fd = accept(server_fd_, (struct sockaddr *)&client_addr, &client_len);
    if (client_fd == -1) {
        perror("accept failed");
        return;
    }
    
    // 输出客户端连接信息
    std::cout << "New connection from " << inet_ntoa(client_addr.sin_addr) 
              << ":" << ntohs(client_addr.sin_port) << std::endl;

    // 设置客户端套接字为非阻塞模式
    int flags = fcntl(client_fd, F_GETFL, 0);
    if (flags == -1 || fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl failed");
        close(client_fd);
        return;
    }

    // 将客户端套接字添加到epoll，使用边缘触发模式(ET)
    struct epoll_event event;
    event.data.fd = client_fd;
    // 使用边缘触发的读事件
    event.events = EPOLLIN | EPOLLET;  
    if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, client_fd, &event) == -1) {
        perror("epoll_ctl failed");
        close(client_fd);
        return;
    }

    // 记录连接时间
    {
        std::lock_guard<std::mutex> lock(connection_mutex_);
        connection_times_[client_fd] = std::chrono::steady_clock::now();
    }
}

// 处理客户端数据
void HttpServer::handle_client_data(int client_fd) {
    // 更新连接时间
    {
        std::lock_guard<std::mutex> lock(connection_mutex_);
        connection_times_[client_fd] = std::chrono::steady_clock::now();
    }

    // 读取客户端数据
    char buffer[BUFFER_SIZE];
    ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);
    
    if (bytes_read == -1) {
        perror("read failed");
        close_connection(client_fd);
        return;
    } 
    // 客户端关闭连接
    else if (bytes_read == 0) {
        std::cout << "Client closed connection" << std::endl;
        close_connection(client_fd);
        return;
    }

    // 确保字符串以null结尾
    buffer[bytes_read] = '\0';
    std::string request_str(buffer);

    // 解析HTTP请求
    HttpRequest request;
    if (!parse_request(request_str, request)) {
        // 发送400 Bad Request响应
        send_response(client_fd, create_error_response(400, "Bad Request"));
        close_connection(client_fd);
        return;
    }

    // 将请求处理任务添加到线程池
    thread_pool_.enqueue([this, client_fd, request]() mutable {
        handle_request(client_fd, request);
    });
}

// 处理HTTP请求
void HttpServer::handle_request(int client_fd, const HttpRequest& request) {
    HttpResponse response;
    
    // 根据请求方法和路径生成响应
    if (request.method == GET) {
        // 处理GET请求
        std::string file_path = request.path;
        
        // 默认路径
        if (file_path == "/") {
            file_path = "/index.html";
        }
        
        // 二进制形式尝试打开文件
        std::ifstream file(std::string("www") + file_path, std::ios::binary);
        if (file) {
            // 获取文件大小
            file.seekg(0, std::ios::end);
            size_t file_size = file.tellg();
            file.seekg(0, std::ios::beg);
            
            // 读取文件内容
            response.body.resize(file_size);
            file.read(&response.body[0], file_size);
            
            // 设置响应头
            response.version = "HTTP/1.1";
            response.status_code = 200;
            response.status_msg = "OK";

            // 设置Content-Type
            // 提取文件扩展名.html, html
            std::string ext = file_path.substr(file_path.find_last_of(".") + 1);
            // 根据文件扩展名设计响应头类型(MIME)
            response.headers["Content-Type"] = get_mime_type(ext);
            
            response.headers["Content-Length"] = std::to_string(file_size);
            response.headers["Connection"] = "keep-alive";
        } else {
            // 文件不存在，返回404
            response = create_error_response(404, "Not Found");
        }
    } else if (request.method == POST) {
        // 简单处理POST请求，返回接收到的数据
        response.version = "HTTP/1.1";
        response.status_code = 200;
        response.status_msg = "OK";
        response.headers["Content-Type"] = "text/plain"; // 纯文本
        response.headers["Connection"] = "keep-alive";
        response.body = "Received POST data: " + request.body;
        response.headers["Content-Length"] = std::to_string(response.body.size());
    } else {
        // 不支持的方法
        response = create_error_response(501, "Not Implemented");
    }
    
    // 发送响应
    send_response(client_fd, response);
    
    // 检查是否需要保持连接
    auto conn_it = request.headers.find("Connection");
    if (conn_it != request.headers.end() && conn_it->second == "close") {
        close_connection(client_fd);
    }
}
// 解析HTTP请求
bool HttpServer::parse_request(const std::string& request_str, HttpRequest& request) {
    std::istringstream iss(request_str);
    std::string line;
    
    // 解析请求行
    if (!std::getline(iss, line)) {
        return false;
    }
    
    // 移除可能的回车符
    line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
    
    std::istringstream request_line(line);
    //从 request_line 流中提取数据
    std::string method_str, path, version;
    
    //按空格分割提取
    if (!(request_line >> method_str >> path >> version)) {
        return false;
    }
    
    // 解析方法
    if (method_str == "GET") {
        request.method = GET;
    } else if (method_str == "POST") {
        request.method = POST;
    } else {
        request.method = UNSUPPORTED;
    }
    
    request.path = path;
    request.version = version;
    
    // 解析请求头
    while (std::getline(iss, line)) {
        // 移除可能的回车符
        line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
        
        // 空行表示头部结束
        if (line.empty()) {
            break;
        }
        
        //查找冒号位置
        size_t colon_pos = line.find(':');
        if (colon_pos == std::string::npos) {
            return false;
        }
        //提取键值对 例如 "Content-Type: application/json"
        std::string key = line.substr(0, colon_pos);
        std::string value = line.substr(colon_pos + 1);
        
        // 移除值value前面的空格
        size_t space_pos = value.find_first_not_of(" ");
        if (space_pos != std::string::npos) {
            value = value.substr(space_pos);
        }
        
        request.headers[key] = value;
    }
    
    // 解析请求体(仅POST方法)，"Content-Length" 表示请求体字节数
    if (request.method == POST && request.headers.find("Content-Length") != request.headers.end()) {
        try {
            // 将 Content-Length 的值（字符串）转换为无符号整数
            size_t content_length = std::stoul(request.headers["Content-Length"]);
            // 从输入流中提取指定长度的内容作为请求体
            request.body = iss.str().substr(iss.tellg(), content_length);
        } catch (...) {
            return false;
        }
    }
    
    return true;
}

// 创建错误响应
HttpResponse HttpServer::create_error_response(int status_code, const std::string& status_msg) {
    HttpResponse response;
    response.version = "HTTP/1.1";
    response.status_code = status_code;
    response.status_msg = status_msg;
    response.body = "<html><head><title>" + std::to_string(status_code) + " " + status_msg + "</title></head>"
                   "<body><h1>" + std::to_string(status_code) + " " + status_msg + "</h1></body></html>";
    response.headers["Content-Type"] = "text/html";
    response.headers["Content-Length"] = std::to_string(response.body.size());
    response.headers["Connection"] = "close";
    return response;
}

// 发送响应
void HttpServer::send_response(int client_fd, const HttpResponse& response) {
    // 构建响应行
    std::string response_str = response.version + " " + std::to_string(response.status_code) + " " + response.status_msg + "\r\n";
    
    // 添加响应头
    for (const auto& header : response.headers) {
        response_str += header.first + ": " + header.second + "\r\n";
    }
    
    // 空行分隔头部和 body
    response_str += "\r\n";
    
    // 添加响应体
    response_str += response.body;
    
    // 发送响应
    ssize_t bytes_sent = send(client_fd, response_str.c_str(), response_str.size(), 0);
    if (bytes_sent == -1) {
        std::cerr << "send failed: " << strerror(errno) << std::endl;
        close_connection(client_fd);
    }
}

// 关闭客户端连接
void HttpServer::close_connection(int client_fd) {
    // 从epoll中移除
    epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, client_fd, nullptr);
    
    // 关闭文件描述符
    close(client_fd);
    
    // 从连接时间映射中移除
    {
        std::lock_guard<std::mutex> lock(connection_mutex_);
        connection_times_.erase(client_fd);
    }
}

// 检查超时连接
void HttpServer::check_timeouts() {
    auto now = std::chrono::steady_clock::now();
    std::vector<int> to_close;
    
    {
        std::lock_guard<std::mutex> lock(connection_mutex_);
        
        // 找出超时的连接
        for (const auto& entry : connection_times_) {
            auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - entry.second);
            if (duration.count() > TIMEOUT) {
                to_close.push_back(entry.first);
                std::cout << "Connection " << entry.first << " timed out" << std::endl;
            }
        }
    }
    
    // 关闭超时连接
    for (int fd : to_close) {
        close_connection(fd);
    }
}

// 获取MIME类型
std::string HttpServer::get_mime_type(const std::string& ext) {
    if (ext == "html" || ext == "htm") return "text/html";
    if (ext == "css") return "text/css";
    if (ext == "js") return "application/javascript";
    if (ext == "jpg" || ext == "jpeg") return "image/jpeg";
    if (ext == "png") return "image/png";
    if (ext == "gif") return "image/gif";
    return "application/octet-stream";
}
    